package model.doe;

import java.awt.image.BufferedImage;
import java.util.Arrays;

public class GaussHermiteModan extends AbstractDoe {
	double e, arg, w2, MIN_VALUE_DOE = 0, MAX_VALUE_DOE = 0;
	int flag = 0, l1, l2;
	private double[][] compulateMatrix;
	private double doeStep;

	@Deprecated
	public GaussHermiteModan() {

		w2 = 0;

		e = 0;
		l1 = 0;

		widthPointsNumber = 0;
		heightPointsNumber = 0;
	}

	public GaussHermiteModan(double doeHeight, double doeWidth, double doeStep, double radius, int n1, int n2) {
		mod_init(radius, n1, n2, doeStep, doeWidth, doeHeight);
		this.doeStep = doeStep;
		widthPointsNumber = (int) (doeWidth / doeStep);
		heightPointsNumber = (int) (doeHeight / doeStep);
		compulateMatrix = new double[widthPointsNumber][heightPointsNumber];
		setDoeFormType(AbstractDoe.DOE_FORM_NON_SYMMETRIC);
	}

	/*public double[][] getMatrix(int type) {
		System.out.println("widthPointsNumber" + widthPointsNumber);
		double[][] matrix = new double[widthPointsNumber][heightPointsNumber];

		for (int i = 0; i < widthPointsNumber; i++) {
			for (int j = 0; j < heightPointsNumber; j++) {

				if (type == MatrixType.ABSOLUTE_AMPLITUDE) {
					matrix[i][j] = Math.abs(mod(i * this.doeStep, j * this.doeStep));
				} else if (type == MatrixType.SIGN_PHASE) {
					matrix[i][j] = (mod(i * this.doeStep, j * this.doeStep) < 0) ? 255 : 0;
				}

				if (matrix[i][j] >= maximumValue) {
					maximumValue = matrix[i][j];
				}

			}

		}
		return matrix;
	}*/

	// ______________________________________________________________________

	double fkt1(int y) {

		// ***************** Factorial computation
		// *******************************

		int i = 1;
		for (int j = 1; j < y; j++) {
			i = i * (j + 1);
		}
		return i;
	}

	// ______________________________________________________________________

	double ermit(double x, int n) {

		// ***************** Hermite polynom ****************************

		double h0, h1, h = 0;
		h0 = 1.0;
		h1 = 2 * x;
		int i;
		if (n == 0) {
			return h0;
		}
		if (n == 1) {
			return h1;
		}
		for (i = 2; i < n + 1; i++) {
			h = 2 * x * h1 - 2 * (i - 1) * h0;
			h0 = h1;
			h1 = h;
		}
		return h;
	}

	// _________________________________________________________________________

	private void mod_init(double w, int k1, int k2, double step, double size1, double size2) {

		// ************ Parameter initialization
		// ***********************************
		double min1, max1, res;
		double par = k1 + k2;

		flag = 1;
		l1 = k1;
		l2 = k2;
		e = (1 / w) * Math.sqrt(2 / (Math.PI * Math.pow(2.0, par) * fkt1(k1) * fkt1(k2)));
		arg = Math.sqrt(2) / w;
		w2 = w * w;
		min1 = mod(0, 0);
		max1 = mod(0, 0);
		for (double u = -size1 / 2; u < size1 / 2; u += step) {
			for (double v = -size2 / 2; v < size2 / 2; v += step) {
				res = mod(u, v);
				if (res < min1)
					min1 = res;
				if (res > max1)
					max1 = res;
			}

		}
		res = Math.abs(max1 - min1);		
		super.maximumValue = max1 + 0.1 * res;
		super.minValue = min1 - 0.1 * res;

	}

	public double mod(double weig, double hig) {

		// ************** Complex function magnitude at single point
		// **************

		if (flag == 0) {
			System.out.println(" parameters must be initializated");
			return 0;
		}
		double psi;

		psi = e * ermit(weig * arg, l1) * ermit(hig * arg, l2) * Math.exp(-((weig * weig) + (hig * hig)) / w2);

		return psi;
	}

	private float amax(float a, float b) {

		float m = a;
		if (b > a)
			m = b;
		return m;
	}

	private float amin(float a, float b) {

		float m = a;
		if (b < a)
			m = b;
		return m;
	}

	@Override
	public double run(int i, int j) {
		
		//System.out.println ("i = " + i * this.doeStep + " j = "+j * this.doeStep);
		return mod(i * this.doeStep, j * this.doeStep);
	}
}
